package com.github.m6d21.sso.support.filter;

import static com.github.m6d21.sso.support.constant.TokenConstant.KEY_TOKEN;

import com.alibaba.fastjson.JSON;
import com.github.m6d21.sso.common.util.HttpFilterHelper;
import com.github.m6d21.sso.support.enums.StatusCode;
import com.github.m6d21.sso.support.model.Response;
import com.github.m6d21.sso.support.model.SsoTokenWrapper;
import com.github.m6d21.sso.support.session.SsoSessionHolder;
import com.github.m6d21.sso.support.token.SsoTokenHelper;
import com.github.m6d21.sso.support.util.ResponseUtil;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 *<p>
 *登录过滤器
 *</p>
 *
 * @author liuyang
 * @date 2018/12/10 Mon 10:00:00
 * @since 1.0.0
 */
//@Component
//@WebFilter(urlPatterns = "/*")
public class SsoLoginFilter implements Filter {

    private static final Logger LOG = LoggerFactory.getLogger(SsoLoginFilter.class);

    private static final List<String> URL_WHITE_LIST = Lists.newArrayList("/web/register",
        "/login.htm", "/login.html", "/web/user/exist/username");

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {

    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain chain)
        throws IOException, ServletException {
        HttpServletRequest request = (HttpServletRequest) servletRequest;
        HttpServletResponse response = (HttpServletResponse) servletResponse;

        if (LOG.isDebugEnabled()) {
            LOG.debug("session-id:{}", request.getRequestedSessionId());
        }
        String url = request.getRequestURI();
        if (isIntercept(url)) {
            boolean verify = verifyToken(request);
            if (!verify) {
                if (HttpFilterHelper.isHtmlRequest(request)) {
                    processHtmlNoAuth(request, response);
                } else {
                    processJsonNoAuth(request, response);
                }
                return;
            }
        }
        //防止重复复登录
//        else if("/web/login".equals(url)){
//            if(verifyToken(request)){
//                processJsonHasLogin(request, response);
//                return;
//            }
//        }
        chain.doFilter(servletRequest, servletResponse);
    }

    @Override
    public void destroy() {
        SsoSessionHolder.clear();
    }

    private boolean verifyToken(HttpServletRequest request) {
        boolean verify = false;
        String token = (String) request.getAttribute(KEY_TOKEN);

        token = (StringUtils.isBlank(token) ? request.getHeader(KEY_TOKEN) : token);
        if (StringUtils.isBlank(token)) {
            Cookie[] cookies = Optional.ofNullable(request.getCookies()).orElse(new Cookie[0]);
            for (Cookie cookie : cookies) {
                if (KEY_TOKEN.equals(cookie.getName())) {
                    token = cookie.getValue();
                    break;
                }
            }
        }

        if (StringUtils.isNotBlank(token)) {
            SsoTokenWrapper ssoTokenWrapper = SsoTokenHelper.verifyToken(token);
            if (ssoTokenWrapper != null) {
                verify = true;
                //登录信息绑定当前线程
                SsoSessionHolder.addAttributes(ssoTokenWrapper.getAttributes());
                SsoSessionHolder.addAttribute("token", ssoTokenWrapper.getToken());
                SsoSessionHolder.addAttribute("uid", ssoTokenWrapper.getUid());
                SsoSessionHolder.addAttribute("username", ssoTokenWrapper.getUsername());
                SsoSessionHolder.addAttribute("displayName", ssoTokenWrapper.getDisplayName());
                SsoSessionHolder.addAttribute("phone", ssoTokenWrapper.getPhone());
            }
        }

        return verify;
    }

    private boolean isIntercept(String url) {
        return !(isExcludeUrl(url) || HttpFilterHelper.isStaticResource(url));
    }

    private boolean isExcludeUrl(String url) {
        return url.endsWith("/login")
            || url.contains("/web/login")
            || URL_WHITE_LIST.contains(url);
    }

    private void processHtmlNoAuth(HttpServletRequest request, HttpServletResponse response) {
        try {
            String url = request.getRequestURI();
            response.setHeader("Content-type", "text/html");
            response.setCharacterEncoding("UTF-8");
            response.sendRedirect("/login.html" + "");
        } catch (IOException e) {
            LOG.error("重定向失败：error:{}", e);
        }
    }

    private void processJsonNoAuth(HttpServletRequest request, HttpServletResponse response) {
        try {
            Response body = ResponseUtil.fail(StatusCode.TOKEN_INVALID.getCode(), "请求失败，请登录后重试");
            response.setHeader("Content-type", "application/json;charset=UTF-8");
            response.setCharacterEncoding("UTF-8");
            PrintWriter out = response.getWriter();
            out.print(JSON.toJSONString(body));
        } catch (IOException e) {
            LOG.error("处理响应异常：error:{}", e);
        }
    }

    private void processJsonHasLogin(HttpServletRequest request, HttpServletResponse response) {
        try {
            Map<String, Object> token = Maps.newHashMap();
            token.put("token", SsoSessionHolder.getToken());
            Response body = ResponseUtil.success(token);
            response.setHeader("Content-type", "application/json;charset=UTF-8");
            response.setCharacterEncoding("UTF-8");
            PrintWriter out = response.getWriter();
            out.print(JSON.toJSONString(body));
        } catch (IOException e) {
            LOG.error("处理响应异常：error:{}", e);
        }
    }

}
